package stream.ThreadSafe;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Zhongzhicong
 * @date 2024/10/28 16:26
 * @version：1.0
 *
 * 线程不安全示例
 * 如果多个线程对同一个共享数据进行访问而不采取同步操作的话，那么操作的结果是不一致的。
 * 以下代码演示了 1000 个线程同时对 cnt 执行自增操作，操作结束之后它的值有可能小于 1000。
 */
public class ThreadUnsafeExample {

    private int cnt = 0;
//    private volatile int cnt = 0; //volatile关键字只能保证可见性，不能保证线程安全
//    private final AtomicInteger cnt = new AtomicInteger(0);//AtomicInteger线程安全

    public void add() {
        cnt++;
//        cnt.addAndGet(1);
//        cnt.incrementAndGet();
    }

    public int get() {
        return cnt;
//        return cnt.get();
    }

    public static class AtomicExample {
        private AtomicInteger cnt = new AtomicInteger();

        public void add() {
            cnt.incrementAndGet();
        }

        public int get() {
            return cnt.get();
        }
    }
    public static class AtomicSynchronizedExample {
        private int cnt = 0;

        public synchronized void add() {
            cnt++;
        }

        public synchronized int get() {
            return cnt;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        final int threadSize = 1000;
//        ThreadUnsafeExample example = new ThreadUnsafeExample();
//        AtomicExample example = new AtomicExample(); // 只修改这条语句
        AtomicSynchronizedExample example = new AtomicSynchronizedExample(); // 只修改这条语句

        final CountDownLatch countDownLatch = new CountDownLatch(threadSize);
        ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < threadSize; i++) {
            executorService.execute(() -> {
                example.add();
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        System.out.println(example.get());
    }
}
